/* The Generic Queue.  Works like a queue
 * Tyler Wozniak & Andrew Hall
 */


#ifndef QUEUE
#define QUEUE
#include "imports.h"
#include "Node.h"

template <typename T>
class Queue
{
private:
	int size; //The size of the queue
	Node<T>* front; //The front node
	Node<T>* back; //the back node
public:
	//Default constructor
	Queue()
	{
		size = 0;
		front = NULL;
		back = NULL;
	}

	//returns the length of the queue
	int Length() const
	{
		return size;
	}

	//Enqueue function implemented with += operator
	void operator+=(T data)
	{
		Node<T>* nodeToBeAdded = new Node<T>(data,size);

		if(!front)
		{
			front = nodeToBeAdded;
			back = front;
		}
		else
		{
			back->nextNode = nodeToBeAdded;
			back = back->nextNode;
		}

		size++;
	}

	//Dequeue function implemented with -- operator
	T operator--()
	{
		Node<T>* temp;

		if(!front)
		{
			return NULL;
		}
		else
		{
			temp = front;
			front = front->nextNode;
			size--;
			T retData = temp->data;
			delete temp;
			return retData;
		}
	}

	//returns the data at the front of the queue without dequeuing
	T peek() const
	{
		if(front)
		{
			return front->data;
		}
		else 
			return NULL;
	}

	//Returns if the queue is empty
	inline bool isEmpty() const
	{
		return !size;
	}

	//Dequeues the entire queue
	void clear()
	{
		while(front)
		{
			--(*this);
		}
	}

	//Deep copy constructor
	Queue(const Queue<T>& other)
	{
		Node<T>* temp = other.top;
		while(temp)
		{
			this += temp->data;
			temp = temp->nextNode;
		}
	}

	//Deep copy assignment operator
	Queue<T> operator=(const Queue<T>& other)
	{
		clear();
		Node<T>* temp = other.top;
		while(temp)
		{
			this += temp->data;
			temp = temp->nextNode;
		}

		return *this;
	}

	//Destructor
	~Queue()
	{
		clear();
	}
};

#endif